//
// Created by benxb on 2021/11/2.
//

#ifndef BENXDB_ACTIVE_DATA_PAGE_H
#define BENXDB_ACTIVE_DATA_PAGE_H

#include <type/value.h>
#include <vector>
#include <compress/compressor.h>
#include <storage/disk/column_storage.h>
#include "common/config.h"
#include "storage/page.h"

namespace benxdb {

/**
 * ActiveDataPage store data_ in memory, data_ can be append into the page and query.
 * When the page is full, it changes to ReadOnlyDataPage
 *
 * Active page format:
 *  ---------------------------------------------------------
 *  | HEADER | Record1 | Record2
 *  ---------------------------------------------------------
 *
 *  Header format (size in bytes):
 *  ----------------------------------------------------------------------------
 *  | SizeColumn (4)| RecordCount (4)| FreeSpaceOffset (4)|
 *  ----------------------------------------------------------------------------
 *
 */
class ActiveDataPage : public Page {
public:
    explicit ActiveDataPage(TypeId type){
        SetColumnType(type);
        SetRecordCount(0);
        SetFreeSpaceOffset(OFFSET_FIRST_RECORD);
    }
    ~ActiveDataPage() = default;

    /**
     * Update value in the offset
     * @param offset
     * @param val
     * @return true if successfully updated
     */
    bool UpdateValue(uint32_t offset, Value val);

    /**
     * Append a new value into the page
     * @param val
     * @return true if successfully append
     */
    bool Append(const Value& val);

    bool Delete(uint32_t offset);

    /**
     * Get total count of the column in this page
     * @return record size
     */
    uint32_t GetRecordCount() {
//        return *reinterpret_cast<uint32_t *>(GetData() + OFFSET_RECORD_COUNT);
        return record_count_;
    }

    /**
     * return the size in byte of the column
     * @return
     */
    uint32_t GetSizeColumn() {
//        uint32_t value_id = *reinterpret_cast<uint32_t *>(GetData() + OFFSET_VALUE_TYPE);
//        return Value(TypeId(value_id)).GetLength();
        return Value(TypeId(value_type_id_)).GetLength();
    }

    char* GetFirstRecordSlot() {
        return GetData() + OFFSET_FIRST_RECORD;
    }


    TypeId GetColumnType() {
        // return TypeId(*reinterpret_cast<uint32_t *>(GetData() + OFFSET_VALUE_TYPE));
        return value_type_id_;
    }

    int64_t FlushPage(std::string data_file);

    void Clear();

private:
    static constexpr size_t OFFSET_VALUE_TYPE = 0;
    static constexpr size_t OFFSET_RECORD_COUNT = 4;
    static constexpr size_t OFFSET_FREE_SPACE_OFFSET = 8;
    static constexpr size_t OFFSET_FIRST_RECORD = 0;

    TypeId value_type_id_;
    uint32_t record_count_;
    uint32_t free_space_offset_;

    /**
     * Set the offset of free space
     * @param free_space_offset
     */
    void SetFreeSpaceOffset(uint32_t free_space_offset) {
        // memcpy(GetData() + OFFSET_FREE_SPACE_OFFSET, &free_space_offset, sizeof(uint32_t));
        free_space_offset_ = free_space_offset;
    }

    void SetColumnType(TypeId type) {
        // memcpy(GetData() + OFFSET_VALUE_TYPE, &type, sizeof(uint32_t));
        value_type_id_ = type;
    }

    uint32_t GetFreeSpaceOffset() {
        // return *reinterpret_cast<uint32_t *>(GetData() + OFFSET_FREE_SPACE_OFFSET);
        return free_space_offset_;
    }

    /**
     * Set the number of record in this page
     * @param record_count
     */
    void SetRecordCount(uint32_t record_count) {
        // memcpy(GetData() + OFFSET_RECORD_COUNT, &record_count, sizeof(uint32_t));
        record_count_ = record_count;
    }

    char* GetSlotOfRecord(uint32_t offset);

    char *GetSlotOfLastRecord();

    uint32_t GetFreeSpace();

    char *GetFirstValuePtr();
};

}


#endif //BENXDB_ACTIVE_DATA_PAGE_H
